package org.ccay.async.conduit;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtils;
import org.ccay.async.AsyncMessage;
import org.ccay.async.ContextAwareMessage;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.log.ILogger;
import org.ccay.core.request.IRequestContext;
import org.ccay.core.request.impl.RequestContext;

/**
 * 具有上下文感知能力的异步通道。
 * 	
 */
public class ContextAwareConduit extends AbstractAsyncConduit {
	
	/** 原始的异步通道 **/
	private AsyncConduit conduit;
	private static ILogger log = CcayLoggerFactory.getLogger(ContextAwareConduit.class);
	/**
	 * 构造器
	 * 
	 * @param conduit
	 */
	public ContextAwareConduit(AsyncConduit conduit) {
		this.conduit = conduit;
	}

	/* (non-Javadoc)
	 * @see org.ccay.async.conduit.AsyncConduit#handle(org.ccay.async.AsyncMessage)
	 */
	public void handle(AsyncMessage message) {
		// 将普通的异步消息转换成具有上下文传递能力的ContextAwareMessage
		ContextAwareMessage ctxAwareMessage = new ContextAwareMessage(message);

		// 获取当前请求上下文中的相关信息
		IRequestContext ctx = RequestContext.getCurrent(true);

		if (ctx == null) {
			// 调用原始的消息通道来发送消息
			this.conduit.handle(message);
			return;
		}
		IRequestContext cloneCtx = new RequestContext();
		try {
			BeanUtils.copyProperties(cloneCtx, ctx);
		} catch (IllegalAccessException e) {
			log.error(e);
		} catch (InvocationTargetException e) {
			log.error(e);
		}
 
		preProcessContext(cloneCtx);
		ctxAwareMessage.setContext(IRequestContext.class, cloneCtx);

		// 调用原始的消息通道来发送消息
		this.conduit.handle(ctxAwareMessage);
	}

	/** 
	 * 预处理上下文
	 * @param cloneCtx
	 */
	private void preProcessContext(IRequestContext cloneCtx) {
		RequestContext realContext = (RequestContext)cloneCtx;
		
		Map<String, Serializable> sessionm = new HashMap<String, Serializable>(cloneCtx.getSession());
		Map<String, Object> sitemm = new HashMap<String, Object>(cloneCtx.getItems());
		//清除session和item中的 不可序列化的对象
		sessionm.remove("Security.Stack");
		sitemm.remove("Security.Stack");
		sessionm.remove("HTTP.Request");
		sitemm.remove("HTTP.Request");
		realContext.setItems(sitemm);
		realContext.setSession(sessionm);
		for(Entry<String, Object> en: cloneCtx.getItems().entrySet()){
			if(en.getValue() != null && !(en.getValue() instanceof Serializable)){
				log.error("Object "+ en.getKey() +" is not serializable in requestContext, it will not work if you use jms condult");
			}
		}		
	}
}
